package com.eian.boot.common.id.service;

import com.eian.boot.common.id.IdHelper;
import com.eian.boot.common.id.enums.IdContentType;
import com.eian.boot.common.id.enums.IdTemplateType;
import com.eian.boot.common.id.exception.IdGenerationException;
import com.eian.boot.common.id.formatter.IdFormatter;
import com.eian.boot.common.id.model.BatchIdConfig;
import com.eian.boot.common.id.obfuscator.IdObfuscator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 批量ID生成服务
 * 支持卡密、优惠券等场景的批量ID生成
 *
 * @author alex.meng
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BatchIdService {

    /**
     * 单次生成的最大数量（防止内存溢出）
     */
    private static final int MAX_BATCH_SIZE = 100_000;
    /**
     * 分批处理的阈值
     */
    private static final int BATCH_THRESHOLD = 10_000;
    /**
     * 去重最大重试次数
     */
    private static final int MAX_RETRY_TIMES = 3;
    private final IdFormatter idFormatter;
    private final IdObfuscator idObfuscator;
    @Autowired(required = false)
    private IdFormatService idFormatService;

    /**
     * 基于数据库模板配置批量生成ID
     *
     * @param bizType 业务类型
     * @param count   生成数量
     * @return ID列表
     */
    public List<String> generateBatch(String bizType, int count) {
        validateCount(count);

        if (idFormatService == null) {
            throw new IllegalStateException("ID格式化服务未配置，请检查数据源配置");
        }

        log.debug("基于模板配置批量生成ID：bizType={}, count={}", bizType, count);

        // 判断是否需要分批处理
        if (count > BATCH_THRESHOLD) {
            return generateInBatches(bizType, count);
        }

        // 直接生成
        List<String> ids = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            ids.add(idFormatService.generateIdByConfig(bizType));
        }

        log.info("批量生成ID完成：bizType={}, count={}", bizType, ids.size());
        return ids;
    }

    /**
     * 基于自定义配置批量生成ID
     *
     * @param config 自定义配置
     * @param count  生成数量
     * @return ID列表
     */
    public List<String> generateBatch(BatchIdConfig config, int count) {
        validateCount(count);
        validateConfig(config);

        log.debug("基于自定义配置批量生成ID：contentType={}, count={}", config.getContentType(), count);

        // 判断是否需要分批处理
        if (count > BATCH_THRESHOLD) {
            return generateInBatchesWithConfig(config, count);
        }

        // 直接生成
        List<String> ids = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            ids.add(generateSingleId(config));
        }

        log.info("批量生成ID完成：contentType={}, count={}", config.getContentType(), ids.size());
        return ids;
    }

    /**
     * 基于数据库模板配置批量生成唯一ID（带去重）
     *
     * @param bizType 业务类型
     * @param count   生成数量
     * @return 唯一ID集合
     */
    public Set<String> generateBatchUnique(String bizType, int count) {
        return generateBatchUnique(bizType, count, MAX_RETRY_TIMES);
    }

    /**
     * 基于数据库模板配置批量生成唯一ID（带去重和重试）
     *
     * @param bizType  业务类型
     * @param count    生成数量
     * @param maxRetry 最大重试次数
     * @return 唯一ID集合
     */
    public Set<String> generateBatchUnique(String bizType, int count, int maxRetry) {
        validateCount(count);

        log.debug("批量生成唯一ID：bizType={}, count={}, maxRetry={}", bizType, count, maxRetry);

        Set<String> uniqueIds = new HashSet<>(count);
        int attempts = 0;

        while (uniqueIds.size() < count && attempts < maxRetry) {
            int needed = count - uniqueIds.size();
            // 生成更多ID以应对去重后的数量减少（增加20%冗余）
            int generateCount = (int) (needed * 1.2);

            List<String> batch = generateBatch(bizType, generateCount);
            uniqueIds.addAll(batch);

            attempts++;
            log.debug("去重进度：当前={}, 目标={}, 尝试次数={}", uniqueIds.size(), count, attempts);
        }

        if (uniqueIds.size() < count) {
            log.warn("批量生成唯一ID未达到目标数量：实际={}, 目标={}, 尝试次数={}", uniqueIds.size(), count, attempts);
        }

        // 确保返回数量不超过请求数量
        List<String> result = new ArrayList<>(uniqueIds);
        if (result.size() > count) {
            result = result.subList(0, count);
        }

        log.info("批量生成唯一ID完成：bizType={}, count={}", bizType, result.size());
        return new LinkedHashSet<>(result);
    }

    /**
     * 基于自定义配置批量生成唯一ID（带去重）
     *
     * @param config 自定义配置
     * @param count  生成数量
     * @return 唯一ID集合
     */
    public Set<String> generateBatchUnique(BatchIdConfig config, int count) {
        return generateBatchUnique(config, count, MAX_RETRY_TIMES);
    }

    /**
     * 基于自定义配置批量生成唯一ID（带去重和重试）
     *
     * @param config   自定义配置
     * @param count    生成数量
     * @param maxRetry 最大重试次数
     * @return 唯一ID集合
     */
    public Set<String> generateBatchUnique(BatchIdConfig config, int count, int maxRetry) {
        validateCount(count);
        validateConfig(config);

        log.debug("批量生成唯一ID：contentType={}, count={}, maxRetry={}", config.getContentType(), count, maxRetry);

        Set<String> uniqueIds = new HashSet<>(count);
        int attempts = 0;

        while (uniqueIds.size() < count && attempts < maxRetry) {
            int needed = count - uniqueIds.size();
            int generateCount = (int) (needed * 1.2);

            List<String> batch = generateBatch(config, generateCount);
            uniqueIds.addAll(batch);

            attempts++;
            log.debug("去重进度：当前={}, 目标={}, 尝试次数={}", uniqueIds.size(), count, attempts);
        }

        if (uniqueIds.size() < count) {
            log.warn("批量生成唯一ID未达到目标数量：实际={}, 目标={}, 尝试次数={}", uniqueIds.size(), count, attempts);
        }

        List<String> result = new ArrayList<>(uniqueIds);
        if (result.size() > count) {
            result = result.subList(0, count);
        }

        log.info("批量生成唯一ID完成：contentType={}, count={}", config.getContentType(), result.size());
        return new LinkedHashSet<>(result);
    }

    /**
     * 分批生成（基于模板配置）
     */
    private List<String> generateInBatches(String bizType, int totalCount) {
        log.info("数量超过阈值，启用分批生成：totalCount={}, batchSize={}", totalCount, BATCH_THRESHOLD);

        List<String> allIds = new ArrayList<>(totalCount);
        int remaining = totalCount;
        int batchNumber = 1;

        while (remaining > 0) {
            int batchSize = Math.min(remaining, BATCH_THRESHOLD);
            log.debug("执行第{}批生成：batchSize={}, remaining={}", batchNumber, batchSize, remaining);

            for (int i = 0; i < batchSize; i++) {
                allIds.add(idFormatService.generateIdByConfig(bizType));
            }

            remaining -= batchSize;
            batchNumber++;
        }

        log.info("分批生成完成：totalCount={}, batches={}", totalCount, batchNumber - 1);
        return allIds;
    }

    /**
     * 分批生成（基于自定义配置）
     */
    private List<String> generateInBatchesWithConfig(BatchIdConfig config, int totalCount) {
        log.info("数量超过阈值，启用分批生成：totalCount={}, batchSize={}", totalCount, BATCH_THRESHOLD);

        List<String> allIds = new ArrayList<>(totalCount);
        int remaining = totalCount;
        int batchNumber = 1;

        while (remaining > 0) {
            int batchSize = Math.min(remaining, BATCH_THRESHOLD);
            log.debug("执行第{}批生成：batchSize={}, remaining={}", batchNumber, batchSize, remaining);

            for (int i = 0; i < batchSize; i++) {
                allIds.add(generateSingleId(config));
            }

            remaining -= batchSize;
            batchNumber++;
        }

        log.info("分批生成完成：totalCount={}, batches={}", totalCount, batchNumber - 1);
        return allIds;
    }

    /**
     * 生成单个ID（基于自定义配置）
     */
    private String generateSingleId(BatchIdConfig config) {
        // 1. 生成ID主体内容
        Object idContent = generateIdContent(config);

        // 2. 解析前缀
        String prefix = resolveTemplate(config.getPrefixTemplate(), config.getPrefix());

        // 3. 解析后缀
        String suffix = resolveTemplate(config.getSuffixTemplate(), config.getSuffix());

        // 4. 判断是否需要混淆
        String finalIdContent;
        if (Boolean.TRUE.equals(config.getUseObfuscate()) && idContent instanceof Long) {
            finalIdContent = String.valueOf(idObfuscator.obfuscate((Long) idContent));
        } else {
            finalIdContent = String.valueOf(idContent);
        }

        // 5. 格式化ID
        return idFormatter.formatId(
                finalIdContent,
                prefix,
                suffix,
                config.getPadChar(),
                config.getIdLength(),
                config.getPadPosition()
        );
    }

    /**
     * 根据ID内容类型生成ID主体
     */
    private Object generateIdContent(BatchIdConfig config) {
        IdContentType contentType = config.getContentType();
        String bizType = config.getBizType();

        return switch (contentType) {
            case SEGMENT -> {
                if (bizType == null) {
                    throw new IdGenerationException("号段ID生成需要指定bizType");
                }
                yield IdHelper.nextSegmentId(bizType);
            }
            case SEQUENCE -> {
                if (bizType == null) {
                    throw new IdGenerationException("序列号生成需要指定bizType");
                }
                yield IdHelper.nextSequence(bizType);
            }
            case SNOWFLAKE -> IdHelper.snowflakeId();
            case UUID -> IdHelper.simpleUuid();
            case UUID_STANDARD -> IdHelper.uuid();
            case CUSTOM -> throw new IdGenerationException("自定义批量生成不支持CUSTOM类型，请使用其他类型");
        };
    }

    /**
     * 解析模板
     */
    private String resolveTemplate(IdTemplateType templateType, String fixedValue) {
        if (templateType == IdTemplateType.FIXED) {
            return fixedValue != null ? fixedValue : "";
        }
        return templateType.generate();
    }

    /**
     * 校验生成数量
     */
    private void validateCount(int count) {
        if (count <= 0) {
            throw new IllegalArgumentException("生成数量必须大于0：count=" + count);
        }
        if (count > MAX_BATCH_SIZE) {
            throw new IllegalArgumentException("单次生成数量不能超过" + MAX_BATCH_SIZE + "：count=" + count);
        }
    }

    /**
     * 校验配置
     */
    private void validateConfig(BatchIdConfig config) {
        if (config == null) {
            throw new IllegalArgumentException("批量生成配置不能为空");
        }
        if (config.getContentType() == null) {
            throw new IllegalArgumentException("ID内容类型不能为空");
        }
        if (config.getContentType() == IdContentType.CUSTOM) {
            throw new IllegalArgumentException("批量生成不支持CUSTOM类型");
        }
        if ((config.getContentType() == IdContentType.SEGMENT || config.getContentType() == IdContentType.SEQUENCE)
                && config.getBizType() == null) {
            throw new IllegalArgumentException("号段/序列号生成需要指定bizType");
        }
    }
}

